package com.axon.components.containers
{
	import com.axon.base.interfaces.IAxSetInitialFocus;
	import com.axon.components.interfaces.IAxSmartContainter;
	import com.axon.mvc.events.AxViewEvent;
	import com.axon.mvc.helpers.AxVerbs;
	
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	
	import mx.containers.TitleWindow;
	import mx.controls.Button;
	import mx.core.UIComponent;
	import mx.managers.CursorManager;
	
	public class AxTitleWindowSizeable extends TitleWindow implements IAxSmartContainter, IAxSetInitialFocus
	{
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		private static const HEADER_PADDING:Number = 14;
			
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		private const dragThreshold:int = 2;
		// sanity constraints.  
		private const minSizeWidth:int = 180;  
		private const minSizeHeight:int = 220;
			
		public const cursorSizeNone:int = -1;
		public const cursorSizeNE:int   = 0;
		public const cursorSizeN:int    = 1;
		public const cursorSizeNW:int   = 2;
		public const cursorSizeW:int    = 3;
		public const cursorSizeSW:int   = 4;
		public const cursorSizeS:int    = 5;
		public const cursorSizeSE:int   = 6;
		public const cursorSizeE:int    = 7;
		public const cursorSizeAll:int  = 8;
			
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		private var fVo: Object = null;
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
   		[Inspectable(category="Other")]	public var axInitialFocusControl 	: UIComponent;
   		[Inspectable(category="Other")] public var axHandleEscapeKey 		: Boolean = true;
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		[Embed(source="/com/axon/base/assets/cursorImages/sizeNS.gif")]
		public static var sizeNSCursorSymbol:Class;

		[Embed(source="/com/axon/base/assets/cursorImages/sizeNESW.gif")]
		public static var sizeNESWCursorSymbol:Class;
		
		[Embed(source="/com/axon/base/assets/cursorImages/sizeWE.gif")]
		public static var sizeWECursorSymbol:Class;

		[Embed(source="/com/axon/base/assets/cursorImages/sizeNWSE.gif")]
		public static var sizeNWSECursorSymbol:Class;
									
		[Embed(source="/com/axon/base/assets/cursorImages/sizeAll.gif")]
		public static var sizeAllCursorSymbol:Class;
			
		private var _allowResize: Boolean = true;
		
		private var downX:int;
		private var downY:int;
		private var startLeft:int;
		private var startTop:int;
		private var startHeight:int;
		private var startWidth:int;
			
		private var resizeCursor:int;
		private var currentCursorID:int;
		private var prevCursor:int;
		private var isResizing:Boolean;
			
		public function AxTitleWindowSizeable()
		{
			super();
			addEventListener( KeyboardEvent.KEY_DOWN, onKeyDown );
			isResizing = false;
			currentCursorID = CursorManager.NO_CURSOR;
			prevCursor = cursorSizeNone;
			this.showCloseButton = true;
		}
			
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		private function onKeyDown(event: KeyboardEvent): void
		{
			switch (event.charCode)
			{
				case Keyboard.ESCAPE: 
					if (axHandleEscapeKey) {  
						dispatchEvent( new AxViewEvent(AxVerbs.CANCEL) ); 
						dispatchEvent( new AxViewEvent(AxVerbs.CLOSE) ); } 
					break;
					
				// TODO - Não sei se deve ter aqui.
//				case Keyboard.F5:
//					dispatchEvent( new AxViewEvent(AxVerbs.REFRESH) );
			}
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
   		[Inspectable(category="Size")]
	    public function get allowResize():Boolean
   		{
       		return _allowResize;
   		}

   		public function set allowResize(value:Boolean):void
   		{
       		_allowResize = value;
   		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////

		[Bindable]	public function get vo(): Object					{ return fVo };
					public function set vo(valueObject: Object): void	{ fVo = valueObject };		
					
					public function get initialFocusControl()	: UIComponent	{ return axInitialFocusControl };			
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////

		override protected function createChildren():void
		{
			super.createChildren();

			// make the cursor change to the resize cursor
			this.titleBar.addEventListener(MouseEvent.MOUSE_MOVE, titleBar_resizeMoveListener);
			this.addEventListener(MouseEvent.MOUSE_MOVE, resizeMoveListener);
			
			this.addEventListener(MouseEvent.MOUSE_OUT, cursorMouseOutListener);
			
			// since the titlebar mousedown listener calls startDragging, but the listener is private
			// we will do our checking in the overridden startDragging event for the titlebar
			this.addEventListener(MouseEvent.MOUSE_DOWN, resizeDownListener);
		}
			
		protected function getCursorStyle(x:int, y:int, isTitleBar:Boolean):int
		{
			if (isResizing)
				return resizeCursor;
				
			// the NW corner has to be done in a seperate section because this 
			// corner is twitchy and we add a 1 pix buffer
			if (x >= 0 && x <= dragThreshold + 1 && y >= 0 && y <= dragThreshold + 1)
			{
				return cursorSizeNW;
			} else if (x >= 0 && x <= dragThreshold)
			{
				if (y >= this.height - dragThreshold)
				{
					return cursorSizeSW;
				} else {
					return cursorSizeW;
				}
			} else if (x >= this.width - dragThreshold)
			{
				if (y >= 0 && y <= dragThreshold)
				{
					return cursorSizeNE;
				} else if (y >= this.height - dragThreshold)
				{
					return cursorSizeSE;
				} else {
					return cursorSizeE;
				}					
			} else if (y >= 0 && y <= dragThreshold)
			{
				return cursorSizeN;
			} else if (y >= this.height - dragThreshold)
			{
				return cursorSizeS;

			// if you want to have the "move" style cursor when over the title bar, uncomment the next three lines					
			//				} else if (isTitleBar)
			//				{
			//					return cursorSizeAll;
			}
				return cursorSizeNone;
		}
			
		protected function clearCursor():void
		{
			if (currentCursorID != CursorManager.NO_CURSOR)
			{
				CursorManager.removeCursor(currentCursorID);
				currentCursorID = CursorManager.NO_CURSOR;
			}
			prevCursor = cursorSizeNone;				
		}
		
		/**
		 *  @protected
		 *  Returns the height of the header.
		 */
		override protected function getHeaderHeight():Number
		{
			var headerHeight:Number = getStyle("headerHeight");
			
			if (isNaN(headerHeight))
				headerHeight = measureHeaderText().height + HEADER_PADDING;
			
			return headerHeight;
		}
		
		/**
		 *  @protected. Returns a Rectangle containing the largest piece of header
		 *  text (can be either the title or status, whichever is bigger).
		 */
		protected function measureHeaderText():Rectangle
		{
			var textWidth:Number = 20;
			var textHeight:Number = 14;
			
			if (titleTextField && titleTextField.text)
			{
				titleTextField.validateNow();
				textWidth = titleTextField.textWidth;
				textHeight = titleTextField.textHeight;
			}
			
			if (statusTextField)
			{
				statusTextField.validateNow();
				textWidth = Math.max(textWidth, statusTextField.textWidth);
				textHeight = Math.max(textHeight, statusTextField.textHeight);
			}
			
			return new Rectangle(0, 0, textWidth, textHeight);
		}
								
		protected function adjustCursor(event:MouseEvent, isTitleBar:Boolean):void
		{
			var c:int;
			
			// we only want the move event from the title bar itself, not from it's children
			// otherwise you get weird cursor behavior in the middle of the titlebar
			if (isTitleBar && event.target != titleBar)
			{
				c = cursorSizeAll;
			} else {
				c = getCursorStyle(event.localX, event.localY, isTitleBar);
			}
			
			// don't switch stuff around if we don't have to
			if (c == prevCursor)
			{
				return;
			}
			
			prevCursor = c;
							
			clearCursor();
			
			switch (c) 
			{
					// if you want to have the "move" style cursor when over the title bar, uncomment the next three lines					
					// case cursorSizeAll:
					//     currentCursorID = CursorManager.setCursor(sizeAllCursorSymbol, 2, -10, -10);	
					//     break;
				case cursorSizeE:
				case cursorSizeW:
					currentCursorID = CursorManager.setCursor(sizeWECursorSymbol, 2, -10, -11);     
					break;
				case cursorSizeNW:
				case cursorSizeSE:
					currentCursorID = CursorManager.setCursor(sizeNWSECursorSymbol, 2, -11, -11);
					break;
				case cursorSizeNE:
				case cursorSizeSW:
					currentCursorID = CursorManager.setCursor(sizeNESWCursorSymbol, 2, -11, -10);
					break;
				case cursorSizeN:
				case cursorSizeS:
					currentCursorID = CursorManager.setCursor(sizeNSCursorSymbol, 2, -10, -10);
					break;
			}
		}
					
		protected function titleBar_resizeMoveListener(event:MouseEvent):void
		{
			if (event.target is Button)
			{
				//the base class doesn't give me access to "closeButton", so this
				//is the only way to check if we are over the button
				clearCursor();
				return;
			}

			adjustCursor(event, true);
		}
		
		protected function resizeMoveListener(event:MouseEvent):void
		{
			if (event.localY > getHeaderHeight())  //don't do it twice, the title bar takes care of it
			{
				adjustCursor(event, false);
			}
		}
		
		override protected function startDragging(event:MouseEvent):void
		{
			// check for the threshholds first,  
			// if we are within the threshold do our stuff, else call super 
			var cursorStyle:int = getCursorStyle(event.localX, event.localY, true);
			if (cursorStyle != cursorSizeNone && cursorStyle != cursorSizeAll )
			{
				startSizing(cursorStyle, event.stageX, event.stageY);
			} else {
				super.startDragging(event);
			}
		}
		
		protected function resizeDownListener(event:MouseEvent):void
		{
			// check for the threshholds first, 
			// if we are within the threshold do our stuff, else call super 
			
			if (!_allowResize) return;
			
			var cursorStyle:int = getCursorStyle(event.localX, event.localY, false);
			if (cursorStyle != cursorSizeNone && cursorStyle != cursorSizeAll)
			{
				startSizing(cursorStyle, event.stageX, event.stageY);
			} 				
		}
		
		protected function startSizing(cursor:int, x:int, y:int):void
		{
			downX = x;
			downY = y;
			startHeight = this.height;
			startWidth = this.width;
			startLeft = this.x;
			startTop = this.y;
			resizeCursor = cursor;
			isResizing = true;								
							
			systemManager.addEventListener(
				MouseEvent.MOUSE_MOVE, systemManager_resizeMouseMoveHandler, true);
	
			systemManager.addEventListener(
				MouseEvent.MOUSE_UP, systemManager_resizeMouseUpHandler, true);
	
			stage.addEventListener(
				Event.MOUSE_LEAVE, stage_resizeMouseLeaveHandler);
		}			
	
		protected function stopSizing():void
		{
			isResizing = false;
			
			systemManager.removeEventListener(
				MouseEvent.MOUSE_MOVE, systemManager_resizeMouseMoveHandler, true);
	
			systemManager.removeEventListener(
				MouseEvent.MOUSE_UP, systemManager_resizeMouseUpHandler, true);
	
			stage.removeEventListener(
				Event.MOUSE_LEAVE, stage_resizeMouseLeaveHandler);

			clearCursor();
		}
		
		private function sizeWidth(event:MouseEvent):void
		{
			var tmp:int;
			tmp = startWidth + event.stageX - downX;
			if (tmp >= minSizeWidth)   
			{
				this.width = tmp;
			}				
		}

		private function sizeHeight(event:MouseEvent):void
		{
			var tmp:int;
			tmp = startHeight + event.stageY - downY;
			if (tmp >= minSizeHeight)   
			{
				this.height = tmp;
			}
		}
					
		private function sizeWidth2(event:MouseEvent): int
		{
			return (event.stageX - downX);
		}

		private function sizeHeight2(event:MouseEvent): int
		{
			return (event.stageY - downY);
		}
					
		private function sizeTop(event:MouseEvent):int
		{
			var tmp:int;
			var delta:int = downY - event.stageY; 
			tmp = startHeight + delta;
			if (tmp < minSizeHeight)   
			{					
				delta = minSizeHeight - startHeight;
				tmp = startHeight + delta;					
			}
			
			this.height = tmp;
			return delta;
//			return 0;
		}

		private function sizeLeft(event:MouseEvent):int
		{
			var tmp:int;
			var delta:int = downX - event.stageX;
			tmp = startWidth + delta;
			if (tmp < minSizeWidth)   
			{
				delta = minSizeWidth - startWidth;
				tmp = startWidth + delta;
			}
			
			this.width = tmp;
			return delta;
//			return 0;
		}

		/**
		 *  @private
		 */
		private function systemManager_resizeMouseMoveHandler(event:MouseEvent):void
		{
			var leftDelta:int=0;
			var topDelta:int=0;
							
			switch (resizeCursor)
			{
				case cursorSizeE:
					sizeWidth(event);
					break;
				case cursorSizeSE:
					sizeWidth(event);
					sizeHeight(event);
					break;						
				case cursorSizeS:
					sizeHeight(event);
					break;
				case cursorSizeSW:
					leftDelta = sizeLeft(event);
					sizeHeight(event);
					break;
				case cursorSizeW:
					leftDelta = sizeLeft(event);
					break;
				case cursorSizeNW:
					topDelta = sizeTop(event);
					leftDelta = sizeLeft(event);
					break;
				case cursorSizeN:
					topDelta = sizeTop(event);
					break;
				case cursorSizeNE:
					topDelta = sizeTop(event);
					sizeWidth(event);
					break;
			}
			
			// when sizing, we only want to do the move once (multiple moves cause ugly refresh problems)
			// a move happens when dragging involves the left or top side				
			if (leftDelta != 0 || topDelta != 0)
			{
				move(startLeft - leftDelta, startTop - topDelta);
			}
				
		}
		     
		/**
		 *  @private
		 */
		private function systemManager_resizeMouseUpHandler(event:MouseEvent):void
		{
			stopSizing();
		}
	
		/**
		 *  @private
		 */
		private function stage_resizeMouseLeaveHandler(event:Event):void
		{
			stopSizing();
		}			
		
		private function cursorMouseOutListener(event:MouseEvent):void
		{
			if (!isResizing)
			{
				clearCursor();
			}
		}
	
	}
}